/**
 * Copyright 2023-2023 Huawei Technologies Co., Ltd
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <securec.h>
#include <cstdint>
#include <string>

#include "hilog/log.h"

#include "infra/log/ai_log.h"

#if defined(AI_SUPPORT_LOG_LEVEL_SETTING)
#include "infra/log/log_level.h"
#endif
#include "infra/base/api_export.h"

static const uint32_t BASE_LOG_DOMAIN_ID = 0xD002150;
static const uint32_t LOG_MAX_LEN = 1024;
#if defined(HIAI_DDK)
static const uint32_t LOG_APP_DOMAIN_ID = 0xFFFF;
#endif
static const int LOG_LEVELS[] = {
    LOG_DEBUG, // AI_LOG_DEBUG
    LOG_INFO, // AI_LOG_INFO
    LOG_WARN, // AI_LOG_WARN
    LOG_ERROR, // AI_LOG_ERROR
    LOG_FATAL
};
static const char MODEL_NAMES[][16] = {
    "AI_NPUCL",
    "DNNACL",
    "CPUCL",
    "AI_FMK",
    "HIAI_DDK_MSG"
};

static void StringReplace(std::string& str, const std::string& oldStr, const std::string& newStr)
{
    std::string::size_type pos = 0u;
    while ((pos = str.find(oldStr, pos)) != std::string::npos) {
        str.replace(pos, oldStr.length(), newStr);
        pos += newStr.length();
    }
}

static uint32_t GetDomainID(const char* moduleName)
{
    uint32_t domainID = BASE_LOG_DOMAIN_ID;
    for (size_t i = 0; i < sizeof(MODEL_NAMES) / sizeof(MODEL_NAMES[0]); ++i) {
        if (strncmp(moduleName, MODEL_NAMES[i], strlen(MODEL_NAMES[i])) == 0) {
            return domainID + i + 1;
        }
    }
    return domainID;
}

#ifdef __cplusplus
extern "C" {
#endif
INFRA_API_EXPORT __attribute__((__format__(__printf__, 3, 4))) void AI_Log_Print(
    AI_LogPriority priority, const char* moduleName, const char* fmt, ...)
{
    if (priority < AI_LOG_DEBUG || priority > AI_LOG_ERROR || fmt == nullptr || moduleName == nullptr) {
        return;
    }

    uint32_t domainID = GetDomainID(moduleName);
    va_list arg;
    va_start(arg, fmt);

    AI_LogPriority currLevel = AI_LOG_DEBUG; // 默认日志级别为DEBUG，由系统的级别控制最终日志是否打印。
#if defined(AI_SUPPORT_LOG_LEVEL_SETTING)
    currLevel = AI_Log_GetLevel(moduleName);
#endif

    LogLevel level = static_cast<LogLevel>(LOG_LEVELS[priority]);
#if defined(HIAI_DDK)
    bool isLoggalbe = OH_LOG_IsLoggable(LOG_APP_DOMAIN_ID, moduleName, level);
#else
    bool isLoggalbe = HiLogIsLoggable(domainID, moduleName, level);
#endif
    if (priority >= currLevel && isLoggalbe) {
        char buf[LOG_MAX_LEN] = {0};
        std::string format(fmt);
        StringReplace(format, "%{public}", "%");
        if (vsnprintf_s(buf, sizeof(buf), sizeof(buf) - 1, format.c_str(), arg) > 0) {
#if defined(HIAI_DDK)
            OH_LOG_Print(LOG_APP, level, LOG_APP_DOMAIN_ID, moduleName, "%{public}s", buf);
#else
            HILOG_IMPL(LOG_CORE, level, domainID, moduleName, "%{public}s", buf);
#endif
        }
    }
    va_end(arg);
}

#ifdef __cplusplus
}
#endif
